use std::path::PathBuf;
use std::net::SocketAddr;
use std::convert::Infallible;
use hyper::{Body, Request, Response, Server, StatusCode};
use hyper::service::{make_service_fn, service_fn};
use tokio::fs::{read_dir, read, metadata};
use urlencoding::decode;

#[tokio::main]
async fn main() {
    // 从环境变量获取配置，如果没有设置则使用默认值
    let port = std::env::var("SERVER_PORT").unwrap_or_else(|_| "8080".to_string());
    let addr_old = std::env::var("SERVER_ADDR").unwrap_or_else(|_| "127.0.0.1".to_string());
    let addr_old = addr_old.split('.');
    let mut addr_new = [0; 4];
    if addr_old.clone().count() == 4 {
        for (i, part) in addr_old.enumerate() {
            addr_new[i] = part.parse().unwrap_or(0);
        }
    }

    // 解析端口
    let port: u16 = port.parse().unwrap_or_else(|_| {
        eprintln!("无效的端口号: {}, 使用默认端口 8080", port);
        8080
    });
    let addr = SocketAddr::from((addr_new, port));
    
    let make_svc = make_service_fn(|_conn| async {
        Ok::<_, Infallible>(service_fn(handle_request))
    });

    let server = Server::bind(&addr).serve(make_svc);

    println!("服务器运行在 http://{}", addr);

    if let Err(e) = server.await {
        eprintln!("服务器错误: {}", e);
    }
}

async fn handle_request(req: Request<Body>) -> Result<Response<Body>, Infallible> {
    // 获取请求路径
    let path = req.uri().path();
    let path: String = decode(path).unwrap_or_else(|_| path.into()).into(); // 解码URL
    let root_dir = std::env::var("SERVER_ROOT").unwrap_or_else(|_| ".".to_string());
    let mut file_path = PathBuf::from(root_dir); // 当前目录为根目录
    
    if path != "/" {
        file_path.push(&path[1..]); // 移除开头的斜杠
    }

    // 检查文件/目录是否存在
    match metadata(&file_path).await {
        Ok(meta) => {
            if meta.is_dir() {
                // 处理目录请求
                handle_directory(&file_path, &path).await
            } else {
                // 处理文件请求
                handle_file(&file_path).await
            }
        }
        Err(_) => {
            // 文件不存在
            Ok(Response::builder()
                .status(StatusCode::NOT_FOUND)
                .body(Body::from("<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>未找到</title></head><body><h1>文件未找到: ".to_string() + file_path.to_string_lossy().as_ref() + "</h1></body></html>"))
                .unwrap())
        }
    }
}

async fn handle_directory(path: &PathBuf, url: &str) -> Result<Response<Body>, Infallible> {
    let mut html = String::from("
        <html>
            <head>
                <meta charset=\"utf-8\">
                <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
                <title>目录列表</title>
                <style>
                    body { font-family: sans-serif; margin: 2em; }
                    ul { list-style-type: none; padding: 0; }
                    li { margin: 0.5em 0; }
                    a { text-decoration: none; color: #0366d6; }
                    a:hover { text-decoration: underline; }
                </style>
            </head>
            <body>
                <h1>目录列表</h1>
                <ul>
    ");

    // 添加返回上级目录的链接
    if let Some(parent) = path.parent() {
        if parent != PathBuf::from(".") {
            html.push_str("<li>📁 <a href=\"../\">../</a></li>");
        }
    }

    // 读取目录内容
    match read_dir(path).await {
        Ok(mut entries) => {
            while let Ok(Some(entry)) = entries.next_entry().await {
                let file_name = entry.file_name().into_string().unwrap_or_default();
                let file_type = if entry.metadata().await.map(|m| m.is_dir()).unwrap_or(false) {
                    "📁"
                } else {
                    "📄"
                };
                
                html.push_str(&format!(
                    "<li>{} <a href=\"{}{}\">{}</a></li>",
                    file_type, {
                        if url.ends_with('/') { url.to_string() } else { format!("{}/", url) }
                    }, file_name, file_name
                ));
            }
        }
        Err(_) => {
            return Ok(Response::builder()
                .status(StatusCode::INTERNAL_SERVER_ERROR)
                .body(Body::from("
                <!DOCTYPE html>
                <html><head><meta charset=\"utf-8\"><title>错误</title></head><body><h1>无法读取目录: ".to_string() + path.to_string_lossy().as_ref() + "</h1></body></html>
                "))
                .unwrap());
        }
    }

    html.push_str("</ul></body></html>");

    Ok(Response::builder()
        .header("Content-Type", "text/html")
        .body(Body::from(html))
        .unwrap())
}

async fn handle_file(path: &PathBuf) -> Result<Response<Body>, Infallible> {
    match read(path).await {
        Ok(content) => {
            // 简单的内容类型检测
            let content_type = if let Some(ext) = path.extension() {
                match ext.to_str().unwrap_or("") {
                    "html" => "text/html",
                    "css" => "text/css",
                    "js" => "application/javascript",
                    "png" => "image/png",
                    "jpg" | "jpeg" => "image/jpeg",
                    "gif" => "image/gif",
                    "pdf" => "application/pdf",
                    _ => "application/octet-stream",
                }
            } else {
                "application/octet-stream"
            };

            Ok(Response::builder()
                .header("Content-Type", content_type)
                .body(Body::from(content))
                .unwrap())
        }
        Err(_) => {
            Ok(Response::builder()
                .status(StatusCode::INTERNAL_SERVER_ERROR)
                .body(Body::from("<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>错误</title></head><body><h1>无法读取文件: ".to_string() + path.to_string_lossy().as_ref() + "</h1></body></html>"))
                .unwrap())
        }
    }
}
